package services

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"

	"zwai-app/db"
	"zwai-app/models"
)

// ErrAccountExists 表示要注册的账号已存在
var ErrAccountExists = errors.New("account already exists")

// ErrInvalidInviteCode 表示传入的邀请码无效
var ErrInvalidInviteCode = errors.New("invalid invite code")

// nextInviteCode 从 counters 集合中自增获取最新 seq，并格式化为 6 位邀请码
func nextInviteCode(ctx context.Context) (string, error) {
	coll := db.Client.Database(db.DBName).Collection("counters")
	after := options.After
	res := coll.FindOneAndUpdate(
		ctx,
		bson.M{"_id": "inviteCode"},
		bson.M{"$inc": bson.M{"seq": 1}},
		options.FindOneAndUpdate().SetReturnDocument(after).SetUpsert(true),
	)
	var doc struct{ Seq int }
	if err := res.Decode(&doc); err != nil {
		return "", err
	}
	return fmt.Sprintf("%06d", doc.Seq), nil
}

// RegisterUser 注册新用户，参数 inviteCodeIn 可选
// 返回 userID、生成的邀请码或错误
func RegisterUser(
	ctx context.Context,
	account, username, password, inviteCodeIn string,
) (primitive.ObjectID, string, error) {
	// 0) 校验可选邀请码
	profColl := db.Client.Database(db.DBName).Collection("UserProfile")
	var inviterID primitive.ObjectID
	if inviteCodeIn != "" {
		var inviter models.UserProfile
		err := profColl.FindOne(ctx, bson.M{"inviteCode": inviteCodeIn}).Decode(&inviter)
		if err != nil {
			if err == mongo.ErrNoDocuments {
				return primitive.NilObjectID, "", ErrInvalidInviteCode
			}
			return primitive.NilObjectID, "", err
		}
		inviterID = inviter.UserID
	}

	// 1) 插入 User
	userColl := db.Client.Database(db.DBName).Collection("User")
	u := models.User{
		Account:   account,
		Username:  username,
		Password:  password,
		CreatedAt: time.Now(),
	}
	res, err := userColl.InsertOne(ctx, u)
	if err != nil {
		var we mongo.WriteException
		if errors.As(err, &we) {
			for _, e := range we.WriteErrors {
				// 账号唯一约束冲突
				if e.Code == 11000 && strings.Contains(e.Message, "account_1") {
					return primitive.NilObjectID, "", ErrAccountExists
				}
			}
		}
		return primitive.NilObjectID, "", err
	}
	userID := res.InsertedID.(primitive.ObjectID)

	// 2) 生成自己的邀请码
	inviteCodeOut, err := nextInviteCode(ctx)
	if err != nil {
		return primitive.NilObjectID, "", err
	}

	// 3) 插入 UserProfile
	profile := models.UserProfile{
		ID:              userID,
		UserID:          userID,
		MembershipLevel: 0,
		Points:          0,
		InviteCode:      inviteCodeOut,
		Age:             0,
		Gender:          "",
		Birthday:        "",
		Hobbies:         "",
		Address:         "",
		Email:           "",
		Signature:       "",
		AvatarURL:       "",
	}
	if inviterID != primitive.NilObjectID {
		profile.InvitedBy = inviterID
	}

	// 确保 userId 唯一索引由 db.Init 完成，仅插入
	if _, err := profColl.InsertOne(ctx, profile); err != nil {
		return primitive.NilObjectID, "", err
	}

	// 4) 更新邀请人 invited 列表
	if inviterID != primitive.NilObjectID {
		_, err := profColl.UpdateOne(ctx,
			bson.M{"userId": inviterID},
			bson.M{"$push": bson.M{"invited": userID}},
		)
		if err != nil {
			return primitive.NilObjectID, "", err
		}
	}

	return userID, inviteCodeOut, nil
}
